package com.crionics.ghtable;

/*
 * (swing1.1beta3)
 * 
 */

import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

/**
 * ColumnGroup.
 *
 * @version 1.0 10/20/98
 * @author Nobuo Tamemasa
 */

public class ColumnGroup {

	protected TableCellRenderer renderer;
	private ColumnGroup parent;
	private List<Object> items = new ArrayList<Object>();
	private String headerValue;
	private int margin = 0;
	private int level = 0;
	private Map<String, Object> clientProperties = new HashMap<String, Object>();

	/**
	 * Instantiates a new column group.
	 *
	 * @param text the text
	 */
	public ColumnGroup(String text) {
		this(null, text);
	}

	/**
	 * Instantiates a new column group.
	 *
	 * @param renderer the renderer
	 * @param headerValue the header value
	 */
	@SuppressWarnings("serial")
    public ColumnGroup(TableCellRenderer renderer, String headerValue) {
		if (renderer == null) {
			this.renderer = new DefaultTableCellRenderer() {
			
				public Component getTableCellRendererComponent(JTable table,
						Object value, boolean isSelected, boolean hasFocus,
						int row, int column) {
					JTableHeader header = table.getTableHeader();
					if (header != null) {
						setForeground(header.getForeground());
						setBackground(header.getBackground());
						setFont(header.getFont());
					}
					setHorizontalAlignment(JLabel.CENTER);
					setText((value == null) ? "" : value.toString());
					setBorder(UIManager.getBorder("TableHeader.cellBorder"));
					return this;
				}
			};
		} else {
			this.renderer = renderer;
		}
		this.headerValue = headerValue;
	}

	/**
	 * Adds the.
	 *
	 * @param columnGroup the column group
	 */
	public void add(ColumnGroup columnGroup) {
		if (columnGroup == null)
			return;
		columnGroup.level = this.level + 1;
		columnGroup.parent = this;
		addItem(columnGroup);
	}

	/**
	 * Adds the.
	 *
	 * @param tableColumn the table column
	 */
	public void add(TableColumn tableColumn) {
		if (tableColumn == null)
			return;
		addItem(tableColumn);
	}

	/**
	 * Adds the item.
	 *
	 * @param obj the obj
	 */
	private void addItem(Object obj) {
		if (!items.contains(obj))
			items.add(obj);
	}

	/**
	 * Gets the column groups.
	 *
	 * @param c the c
	 * @return the column groups
	 */
	public List<ColumnGroup> getColumnGroups(TableColumn c) {
		if (items.contains(c)) {
			return getParents();
		} else {
			for (Object obj : items) {
				if (obj instanceof ColumnGroup) {
					ColumnGroup cGroup = (ColumnGroup) obj;
					List<ColumnGroup> v_ret = cGroup.getColumnGroups(c);
					if (v_ret != null) {
						return v_ret;
					}
				}
			}
		}
		return null;
	}

	/**
	 * Gets the parents.
	 *
	 * @return the parents
	 */
	private List<ColumnGroup> getParents() {
		List<ColumnGroup> result = new ArrayList<ColumnGroup>();
		ColumnGroup g = this;
		do {
			result.add(g);
			g = g.getParent();
		} while (g != null);
		Collections.reverse(result);
		return result;
	}

	/**
	 * Gets the header renderer.
	 *
	 * @return the header renderer
	 */
	public TableCellRenderer getHeaderRenderer() {
		return renderer;
	}

	/**
	 * Sets the header renderer.
	 *
	 * @param renderer the new header renderer
	 */
	public void setHeaderRenderer(TableCellRenderer renderer) {
		if (renderer != null) {
			this.renderer = renderer;
		}
	}

	/**
	 * Gets the header value.
	 *
	 * @return the header value
	 */
	public Object getHeaderValue() {
		return headerValue;
	}

	/**
	 * Gets the size.
	 *
	 * @param table the table
	 * @return the size
	 */
	public Dimension getSize(JTable table) {
		Component comp = renderer.getTableCellRendererComponent(table,
				getHeaderValue(), false, false, -1, -1);
		int width = 0;
		int height = comp.getPreferredSize().height;
		Iterator<Object> iterator = items.iterator();
		while (iterator.hasNext()) {
			Object obj = iterator.next();
			if (obj instanceof TableColumn) {
				width += ((TableColumn) obj).getWidth();
			} else if (obj instanceof ColumnGroup) {
				width += ((ColumnGroup) obj).getSize(table).width;
			}
		}
		return new Dimension(width, height);
	}

	/**
	 * Sets the column margin.
	 *
	 * @param margin the new column margin
	 */
	public void setColumnMargin(int margin) {
		this.margin = margin;
		Iterator<Object> iterator = items.iterator();
		while (iterator.hasNext()) {
			Object obj = iterator.next();
			if (obj instanceof ColumnGroup) {
				((ColumnGroup) obj).setColumnMargin(margin);
			}
		}
	}

	/**
	 * Gets the client properties.
	 *
	 * @return the client properties
	 */
	public Map<String, Object> getClientProperties() {
		return clientProperties;
	}

	/**
	 * Gets the client property.
	 *
	 * @param key the key
	 * @return the client property
	 */
	public Object getClientProperty(String key) {
		return this.clientProperties.get(key);
	}

	/**
	 * Sets the client property.
	 *
	 * @param key the key
	 * @param value the value
	 */
	public void setClientProperty(String key, Object value) {
		this.clientProperties.put(key, value);
	}

	/**
	 * Gets the level.
	 *
	 * @return the level
	 */
	public int getLevel() {
		return level;
	}

	/**
	 * Gets the parent.
	 *
	 * @return the parent
	 */
	public ColumnGroup getParent() {
		return parent;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ColumnGroup clone() {
		ColumnGroup result = new ColumnGroup(this.headerValue);
		result.renderer = this.renderer;
		result.parent = this.parent;
		result.items = this.items;
		result.margin = this.margin;
		result.level = this.level;
		result.clientProperties = this.clientProperties;
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		return headerValue + "=" + items.size();
	}
}